﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
/*
 使用
        Xmal:
        <loc:ControlSlider x:Name="slide1"/>
        <loc:ControlSlider x:Name="slide2" Grid.Row="1"/>
        Code:
        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            var colors = new Color[]
            {
                Colors.Red, Colors.Green, Colors.Black, Colors.Blue, Colors.Purple
            };

            slide1.ChildControls = colors.Select(c => CreateButton(c)).ToArray();
            slide2.ChildControls = colors.Select(c => CreateButton(c)).ToArray();
        }

        static Button CreateButton(Color col)
        {
            return new Button()
            {
                Content = "Mgen",
                Background = new SolidColorBrush(col)
            };
        }
 */
namespace V5_PhoneLibs.Controls {
    [TemplatePart(Name = "PART_Grid", Type = typeof(Grid))]
    public class ControlSlider : Control {
        #region 字段和属性

        bool hasTemplate;
        bool onAnimation;

        Grid grid;
        UIElement curr;
        int currIndex = -1;

        #region ChildControls

        /// <summary>
        /// ChildControls Dependency Property
        /// </summary>
        public static readonly DependencyProperty ChildControlsProperty =
            DependencyProperty.Register("ChildControls", typeof(UIElement[]), typeof(ControlSlider),
                new PropertyMetadata((UIElement[])null,
                    new PropertyChangedCallback(OnChildControlsChanged)));

        /// <summary>
        /// Gets or sets the ChildControls property. This dependency property 
        /// indicates ....
        /// </summary>
        public UIElement[] ChildControls {
            get { return (UIElement[])GetValue(ChildControlsProperty); }
            set { SetValue(ChildControlsProperty, value); }
        }

        /// <summary>
        /// Handles changes to the ChildControls property.
        /// </summary>
        private static void OnChildControlsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            ControlSlider target = (ControlSlider)d;
            UIElement[] oldChildControls = (UIElement[])e.OldValue;
            UIElement[] newChildControls = target.ChildControls;
            target.OnChildControlsChanged(oldChildControls, newChildControls);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the ChildControls property.
        /// </summary>
        protected virtual void OnChildControlsChanged(UIElement[] oldChildControls, UIElement[] newChildControls) {
            if (HasChildren)
                SetCurrent(0, true);
            else
                grid.Children.Clear();
        }

        #endregion

        public bool HasChildren {
            get { return ChildControls != null && ChildControls.Length > 0; }
        }
        #endregion

        #region 方法

        public ControlSlider() {
            DefaultStyleKey = typeof(ControlSlider);
        }


        public override void OnApplyTemplate() {
            base.OnApplyTemplate();

            grid = GetTemplateChild("PART_Grid") as Grid;
            if (grid == null)
                throw new Exception("Grid element required");
            hasTemplate = true;

            if (HasChildren)
                SetCurrent(0, true);
        }


        public void SetCurrent(int idx, bool flyToRight) {
            if (!hasTemplate || ChildControls == null || onAnimation)
                return;

            if (idx < 0) {
                OnMoreLeft(EventArgs.Empty);
                return;
            }
            if (idx >= ChildControls.Length) {
                OnMoreRight(EventArgs.Empty);
                return;
            }

            if (curr != null)
                curr.ManipulationCompleted -= new EventHandler<ManipulationCompletedEventArgs>(curr_ManipulationCompleted);

            var prev = curr;
            if (prev != null)
                Canvas.SetZIndex(prev, 1);

            currIndex = idx;
            curr = ChildControls[idx];
            Canvas.SetZIndex(curr, 0);
            grid.Children.Add(curr);
            curr.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(curr_ManipulationCompleted);

            if (prev != null) {
                onAnimation = true;
                FlipAnimation(prev, flyToRight ? 1.0 : 0.0, null, () => {
                    grid.Children.Remove(prev);
                    prev.Projection = null;
                    onAnimation = false;
                });
            }
        }

        void curr_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) {
            if (e.TotalManipulation.Translation.X < 0)
                SetCurrent(currIndex + 1, false);
            else
                SetCurrent(currIndex - 1, true);
        }

        static void FlipAnimation(UIElement ele, double horizontalPoint, Action onAnimating, Action onAnimated) {
            var planeProjection = new PlaneProjection();
            planeProjection.CenterOfRotationX = horizontalPoint;
            ele.Projection = planeProjection;

            var da = new DoubleAnimation();
            da.From = 0;
            da.To = planeProjection.CenterOfRotationX == 0.0 ? 90 : -90;
            da.Duration = new Duration(TimeSpan.FromMilliseconds(800));
            da.Completed += (ss, ee) => {
                if (onAnimated != null)
                    onAnimated();
            };

            var easing = new CircleEase();
            easing.EasingMode = EasingMode.EaseIn; ;
            da.EasingFunction = easing;

            if (onAnimating != null)
                onAnimating();

            var storyboard = new Storyboard();
            Storyboard.SetTarget(storyboard, planeProjection);
            Storyboard.SetTargetProperty(storyboard, new PropertyPath("RotationY"));

            storyboard.Children.Add(da);
            storyboard.Begin();
        }
        #endregion

        #region 事件
        public event EventHandler MoreLeft;

        protected virtual void OnMoreLeft(EventArgs e) {
            var handler = this.MoreLeft;
            if (handler != null)
                handler(this, e);
        }

        public event EventHandler MoreRight;

        protected virtual void OnMoreRight(EventArgs e) {
            var handler = this.MoreRight;
            if (handler != null)
                handler(this, e);
        }

        #endregion
    }
}
